/**
 * 微信小程序 MQTT 轻量级实现
 * 基于 wx.connectSocket() 实现 MQTT 协议
 * 无需外部依赖
 */

class WxMqtt {
  constructor() {
    this.socket = null;
    this.connected = false;
    this.connecting = false;
    this.messageId = 1;
    this.clientId = '';
    this.keepalive = 60;
    this.pingTimer = null;
    this.callbacks = {
      onConnect: null,
      onMessage: null,
      onClose: null,
      onError: null
    };
  }

  /**
   * 连接到 MQTT 服务器
   * @param {Object} options - 连接选项
   * @param {String} options.host - 服务器地址
   * @param {Number} options.port - 端口
   * @param {String} options.path - WebSocket 路径
   * @param {String} options.clientId - 客户端ID
   * @param {Number} options.keepalive - 心跳间隔
   */
  connect(options) {
    return new Promise((resolve, reject) => {
      if (this.connected) {
        console.log('[WxMqtt] 已经连接');
        resolve({ success: true });
        return;
      }

      if (this.connecting) {
        console.log('[WxMqtt] 正在连接中...');
        reject({ success: false, message: '正在连接中' });
        return;
      }

      this.connecting = true;
      this.clientId = options.clientId || 'wxmp_' + Date.now();
      this.keepalive = options.keepalive || 60;

      // 构建 WebSocket URL
      const protocol = options.ssl ? 'wss' : 'ws';
      const url = `${protocol}://${options.host}:${options.port}${options.path || '/mqtt'}`;
      
      console.log('[WxMqtt] 正在连接:', url);
      console.log('[WxMqtt] 客户端ID:', this.clientId);

      // 创建 WebSocket 连接（使用 SocketTask，避免全局监听器冲突）
      const socketTask = wx.connectSocket({
        url: url,
        protocols: ['mqtt'],  // 🔥 关键：指定使用 MQTT 子协议
        success: () => {
          console.log('[WxMqtt] WebSocket 连接请求已发送（协议：mqtt）');
        },
        fail: (err) => {
          console.error('[WxMqtt] WebSocket 连接失败:', err);
          this.connecting = false;
          reject({ success: false, message: 'WebSocket 连接失败', error: err });
        }
      });

      this.socket = socketTask;

      // WebSocket 打开事件（使用 SocketTask 的实例方法）
      socketTask.onOpen(() => {
        console.log('[WxMqtt] WebSocket 已打开，发送 MQTT CONNECT 包...');
        
        // 发送 MQTT CONNECT 包
        const connectPacket = this.buildConnectPacket();
        socketTask.send({
          data: connectPacket,
          success: () => {
            console.log('[WxMqtt] MQTT CONNECT 包已发送');
          },
          fail: (err) => {
            console.error('[WxMqtt] 发送 CONNECT 包失败:', err);
            this.connecting = false;
            reject({ success: false, message: '发送 CONNECT 包失败', error: err });
          }
        });
      });

      // WebSocket 消息事件（使用 SocketTask 的实例方法）
      socketTask.onMessage((res) => {
        try {
          // 将 ArrayBuffer 转换为 Uint8Array
          const data = new Uint8Array(res.data);
          
          // 解析 MQTT 包类型
          const packetType = (data[0] >> 4) & 0x0F;
          
          console.log('[WxMqtt] 收到 MQTT 包，类型:', packetType);
          
          if (packetType === 2) {
            // CONNACK - 连接确认
            console.log('[WxMqtt] ✅ MQTT 连接成功！');
            this.connected = true;
            this.connecting = false;
            
            // 启动心跳
            this.startPing();
            
            if (this.callbacks.onConnect) {
              this.callbacks.onConnect();
            }
            
            resolve({ success: true });
            
          } else if (packetType === 3) {
            // PUBLISH - 接收消息
            this.handlePublish(data);
            
          } else if (packetType === 13) {
            // PINGRESP - 心跳响应
            console.log('[WxMqtt] 💓 收到心跳响应');
            
          } else if (packetType === 9) {
            // SUBACK - 订阅确认
            console.log('[WxMqtt] ✅ 订阅确认');
          }
          
        } catch (err) {
          console.error('[WxMqtt] 处理消息失败:', err);
        }
      });

      // WebSocket 错误事件（使用 SocketTask 的实例方法）
      socketTask.onError((err) => {
        console.error('[WxMqtt] WebSocket 错误:', err);
        this.connected = false;
        this.connecting = false;
        
        if (this.callbacks.onError) {
          this.callbacks.onError(err);
        }
        
        reject({ success: false, message: 'WebSocket 错误', error: err });
      });

      // WebSocket 关闭事件（使用 SocketTask 的实例方法）
      socketTask.onClose(() => {
        console.log('[WxMqtt] WebSocket 连接关闭');
        this.connected = false;
        this.connecting = false;
        this.stopPing();
        
        if (this.callbacks.onClose) {
          this.callbacks.onClose();
        }
      });
    });
  }

  /**
   * 构建 MQTT CONNECT 包
   */
  buildConnectPacket() {
    const clientIdBytes = this.stringToBytes(this.clientId);
    const protocolName = 'MQTT';
    const protocolNameBytes = this.stringToBytes(protocolName);
    
    // MQTT 固定头
    const fixedHeader = new Uint8Array([
      0x10,  // CONNECT 包类型
      0      // 剩余长度（稍后计算）
    ]);
    
    // 可变头
    const variableHeader = new Uint8Array([
      0x00, protocolNameBytes.length,  // 协议名长度
      ...protocolNameBytes,             // 协议名 "MQTT"
      0x04,                             // 协议级别 (MQTT 3.1.1)
      0x02,                             // 连接标志 (Clean Session)
      (this.keepalive >> 8) & 0xFF,     // Keep Alive MSB
      this.keepalive & 0xFF             // Keep Alive LSB
    ]);
    
    // 有效载荷
    const payload = new Uint8Array([
      0x00, clientIdBytes.length,  // 客户端ID长度
      ...clientIdBytes             // 客户端ID
    ]);
    
    // 计算剩余长度
    const remainingLength = variableHeader.length + payload.length;
    fixedHeader[1] = remainingLength;
    
    // 组合完整数据包
    const packet = new Uint8Array(fixedHeader.length + variableHeader.length + payload.length);
    packet.set(fixedHeader, 0);
    packet.set(variableHeader, fixedHeader.length);
    packet.set(payload, fixedHeader.length + variableHeader.length);
    
    return packet.buffer;
  }

  /**
   * 订阅主题
   * @param {String} topic - 主题
   * @param {Number} qos - QoS 级别 (0, 1, 2)
   */
  subscribe(topic, qos = 0) {
    if (!this.connected) {
      console.error('[WxMqtt] 未连接，无法订阅');
      return Promise.reject({ success: false, message: '未连接' });
    }

    const topicBytes = this.stringToBytes(topic);
    const messageId = this.messageId++;
    
    // 固定头
    const fixedHeader = new Uint8Array([
      0x82,  // SUBSCRIBE 包类型
      0      // 剩余长度（稍后计算）
    ]);
    
    // 可变头 + 载荷
    const variableHeader = new Uint8Array([
      (messageId >> 8) & 0xFF,    // 消息ID MSB
      messageId & 0xFF,           // 消息ID LSB
      0x00, topicBytes.length,    // 主题长度
      ...topicBytes,              // 主题
      qos                         // QoS
    ]);
    
    // 计算剩余长度
    fixedHeader[1] = variableHeader.length;
    
    // 组合数据包
    const packet = new Uint8Array(fixedHeader.length + variableHeader.length);
    packet.set(fixedHeader, 0);
    packet.set(variableHeader, fixedHeader.length);
    
    return new Promise((resolve, reject) => {
      if (!this.socket) {
        reject({ success: false, error: '未连接' });
        return;
      }
      
      this.socket.send({
        data: packet.buffer,
        success: () => {
          console.log('[WxMqtt] ✅ 订阅请求已发送:', topic);
          resolve({ success: true });
        },
        fail: (err) => {
          console.error('[WxMqtt] ❌ 订阅失败:', err);
          reject({ success: false, error: err });
        }
      });
    });
  }

  /**
   * 发布消息
   * @param {String} topic - 主题
   * @param {String} message - 消息内容
   * @param {Number} qos - QoS 级别
   */
  publish(topic, message, qos = 0) {
    if (!this.connected) {
      console.error('[WxMqtt] 未连接，无法发布');
      return Promise.reject({ success: false, message: '未连接' });
    }

    const topicBytes = this.stringToBytes(topic);
    const messageBytes = this.stringToBytes(message);
    
    // 固定头
    const fixedHeader = new Uint8Array([
      0x30,  // PUBLISH 包类型
      0      // 剩余长度（稍后计算）
    ]);
    
    // 可变头 + 载荷
    const variableHeader = new Uint8Array([
      0x00, topicBytes.length,  // 主题长度
      ...topicBytes,            // 主题
      ...messageBytes           // 消息
    ]);
    
    // 计算剩余长度
    const remainingLength = variableHeader.length;
    fixedHeader[1] = remainingLength;
    
    // 组合数据包
    const packet = new Uint8Array(fixedHeader.length + variableHeader.length);
    packet.set(fixedHeader, 0);
    packet.set(variableHeader, fixedHeader.length);
    
    return new Promise((resolve, reject) => {
      if (!this.socket) {
        reject({ success: false, error: '未连接' });
        return;
      }
      
      this.socket.send({
        data: packet.buffer,
        success: () => {
          console.log('[WxMqtt] ✅ 消息已发布:', topic, message);
          resolve({ success: true });
        },
        fail: (err) => {
          console.error('[WxMqtt] ❌ 发布失败:', err);
          reject({ success: false, error: err });
        }
      });
    });
  }

  /**
   * 处理 PUBLISH 消息
   */
  handlePublish(data) {
    try {
      // 解析主题长度
      const topicLengthMSB = data[2];
      const topicLengthLSB = data[3];
      const topicLength = (topicLengthMSB << 8) | topicLengthLSB;
      
      // 提取主题
      const topicBytes = data.slice(4, 4 + topicLength);
      const topic = this.bytesToString(topicBytes);
      
      // 提取消息
      const messageBytes = data.slice(4 + topicLength);
      const message = this.bytesToString(messageBytes);
      
      console.log('[WxMqtt] 📩 收到消息:', topic, message);
      
      if (this.callbacks.onMessage) {
        this.callbacks.onMessage(topic, message);
      }
    } catch (err) {
      console.error('[WxMqtt] 解析 PUBLISH 消息失败:', err);
    }
  }

  /**
   * 启动心跳
   */
  startPing() {
    this.stopPing();
    
    this.pingTimer = setInterval(() => {
      if (this.connected && this.socket) {
        console.log('[WxMqtt] 💓 发送心跳...');
        
        const pingPacket = new Uint8Array([0xC0, 0x00]);
        
        this.socket.send({
          data: pingPacket.buffer,
          success: () => {
            console.log('[WxMqtt] 心跳已发送');
          },
          fail: (err) => {
            console.error('[WxMqtt] 心跳发送失败:', err);
          }
        });
      }
    }, this.keepalive * 1000);
  }

  /**
   * 停止心跳
   */
  stopPing() {
    if (this.pingTimer) {
      clearInterval(this.pingTimer);
      this.pingTimer = null;
    }
  }

  /**
   * 断开连接
   */
  disconnect() {
    return new Promise((resolve) => {
      if (this.socket) {
        // 发送 DISCONNECT 包
        const disconnectPacket = new Uint8Array([0xE0, 0x00]);
        
        this.socket.send({
          data: disconnectPacket.buffer,
          complete: () => {
            this.socket.close({
              success: () => {
                console.log('[WxMqtt] WebSocket 已关闭');
              },
              complete: () => {
                this.connected = false;
                this.connecting = false;
                this.socket = null;
                this.stopPing();
                resolve({ success: true });
              }
            });
          }
        });
      } else {
        resolve({ success: true });
      }
    });
  }

  /**
   * 设置回调函数
   */
  on(event, callback) {
    if (event === 'connect') {
      this.callbacks.onConnect = callback;
    } else if (event === 'message') {
      this.callbacks.onMessage = callback;
    } else if (event === 'close') {
      this.callbacks.onClose = callback;
    } else if (event === 'error') {
      this.callbacks.onError = callback;
    }
  }

  /**
   * 获取连接状态
   */
  isConnected() {
    return this.connected;
  }

  /**
   * 字符串转字节数组
   */
  stringToBytes(str) {
    const bytes = [];
    for (let i = 0; i < str.length; i++) {
      const charCode = str.charCodeAt(i);
      if (charCode < 0x80) {
        bytes.push(charCode);
      } else if (charCode < 0x800) {
        bytes.push(0xC0 | (charCode >> 6));
        bytes.push(0x80 | (charCode & 0x3F));
      } else if (charCode < 0x10000) {
        bytes.push(0xE0 | (charCode >> 12));
        bytes.push(0x80 | ((charCode >> 6) & 0x3F));
        bytes.push(0x80 | (charCode & 0x3F));
      }
    }
    return new Uint8Array(bytes);
  }

  /**
   * 字节数组转字符串
   */
  bytesToString(bytes) {
    let str = '';
    for (let i = 0; i < bytes.length; i++) {
      str += String.fromCharCode(bytes[i]);
    }
    return str;
  }
}

// 导出
module.exports = WxMqtt;

